home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / MNetsrc.hqx / Mac TCP_IP Source v.33 / Other Files.SIT / 8250.c next >
Text File  |  1989-01-13  |  7KB  |  327 lines

  1. /* OS- and machine-dependent stuff for the 8250 asynch chip on a IBM-PC */
  2. #include <stdio.h>
  3. #include "global.h"
  4. #include "asy.h"
  5. #include "8250.h"
  6. #include "iface.h"
  7.  
  8. struct asy asy[ASY_MAX];
  9. unsigned nasy;
  10.  
  11. /* ASY interrupt handlers */
  12. extern void asy0vec(),asy1vec(),asy2vec(),asy3vec(),asy4vec();
  13. void (*handle[])() = {asy0vec,asy1vec,asy2vec,asy3vec,asy4vec};
  14.  
  15. /* Initialize asynch port "dev" */
  16. int
  17. asy_init(dev,arg1,arg2,bufsize)
  18. int16 dev;
  19. char *arg1,*arg2;    /* Attach args for address and vector */
  20. unsigned bufsize;
  21. {
  22.     register unsigned base;
  23.     register struct fifo *fp;
  24.     register struct asy *ap;
  25.     void (*getirq())();
  26.     char i_state;
  27.  
  28.     ap = &asy[dev];
  29.     ap->addr = htoi(arg1);
  30.     ap->vec = htoi(arg2);
  31.     /* Set up receiver FIFO */
  32.     fp = &ap->fifo;
  33.     if((fp->buf = malloc(bufsize)) == NULLCHAR){
  34.         printf("asy%d: No space for rx buffer\r\n");
  35.         fflush(stdout);
  36.         return;
  37.     }
  38.     fp->bufsize = bufsize;
  39.     fp->wp = fp->rp = fp->buf;
  40.     fp->cnt = 0;
  41.  
  42.     base = ap->addr;
  43.  
  44.     /* Purge the receive data buffer */
  45.     (void)inportb(base+RBR);
  46.  
  47.     i_state = disable();
  48.  
  49.     /* Save original interrupt vector, mask state, control bits */
  50.     ap->save.vec = getirq(ap->vec);
  51.     ap->save.mask = getmask(ap->vec);
  52.     ap->save.lcr = inportb(base+LCR);
  53.     ap->save.ier = inportb(base+IER);
  54.     ap->save.mcr = inportb(base+MCR);
  55.  
  56.     /* save speed bytes */
  57.     setbit(base+LCR,LCR_DLAB);
  58.     ap->save.divl = inportb(base+DLL);
  59.     ap->save.divh = inportb(base+DLM);
  60.     clrbit(base+LCR,LCR_DLAB);
  61.  
  62.     /* Set interrupt vector to SIO handler */
  63.     setirq(ap->vec,handle[dev]);
  64.  
  65.     /* Set line control register: 8 bits, no parity */
  66.     outportb(base+LCR,(char)LCR_8BITS);
  67.  
  68.     /* Turn on receive interrupt enable in 8250, leave transmit
  69.      * and modem status interrupts turned off for now
  70.      */
  71.     outportb(base+IER,(char)IER_DAV);
  72.  
  73.     /* Set modem control register: assert DTR, RTS, turn on 8250
  74.      * master interrupt enable (connected to OUT2)
  75.      */
  76.     outportb(base+MCR,(char)(MCR_DTR|MCR_RTS|MCR_OUT2));
  77.  
  78.     /* Enable interrupt */
  79.     maskon(ap->vec);
  80.     restore(i_state);
  81. }
  82. int
  83. asy_stop(iface)
  84. struct interface *iface;
  85. {
  86.     register unsigned base;
  87.     register struct asy *ap;
  88.     char i_state;
  89.  
  90.     ap = &asy[iface->dev];
  91.     base = ap->addr;
  92.  
  93.     /* Purge the receive data buffer */
  94.     (void)inportb(base+RBR);
  95.  
  96.     /* Restore original interrupt vector and 8259 mask state */
  97.     i_state = disable();
  98.     setirq(ap->vec,ap->save.vec);
  99.     if(ap->save.mask)
  100.         maskon(ap->vec);
  101.     else
  102.         maskoff(ap->vec);
  103.  
  104.     /* Restore speed regs */
  105.     setbit(base+LCR,LCR_DLAB);
  106.     outportb(base+DLL,ap->save.divl);    /* Low byte */
  107.     outportb(base+DLM,ap->save.divh);    /* Hi byte */
  108.     clrbit(base+LCR,LCR_DLAB);
  109.  
  110.     /* Restore control regs */
  111.     outportb(base+LCR,ap->save.lcr);
  112.     outportb(base+IER,ap->save.ier);
  113.     outportb(base+MCR,ap->save.mcr);
  114.     restore(i_state);
  115. }
  116. /* Asynchronous line I/O control */
  117. asy_ioctl(interface,argc,argv)
  118. struct interface *interface;
  119. int argc;
  120. char *argv[];
  121. {
  122.     if(argc < 1){
  123.         printf("%d\r\n",asy[interface->dev].speed);
  124.         return 0;
  125.     }
  126.     return asy_speed(interface->dev,atoi(argv[0]));
  127. }
  128. /* Set asynch line speed */
  129. int
  130. asy_speed(dev,speed)
  131. int16 dev;
  132. int speed;
  133. {
  134.     register unsigned base;
  135.     register int divisor;
  136.     char i_state;
  137.  
  138.     if(speed == 0 || dev >= nasy)
  139.         return -1;
  140.     
  141.     base = asy[dev].addr;
  142.     asy[dev].speed = speed;
  143.  
  144.     divisor = BAUDCLK / (long)speed;
  145.  
  146.     i_state = disable();
  147.  
  148.     /* Purge the receive data buffer */
  149.     (void)inportb(base+RBR);
  150.  
  151.     /* Turn on divisor latch access bit */
  152.     setbit(base+LCR,LCR_DLAB);
  153.  
  154.     /* Load the two bytes of the register */
  155.     outportb(base+DLL,(char)(divisor & 0xff));        /* Low byte */
  156.     outportb(base+DLM,(char)((divisor >> 8) & 0xff));    /* Hi byte */
  157.  
  158.     /* Turn off divisor latch access bit */
  159.     clrbit(base+LCR,LCR_DLAB);
  160.  
  161.     restore(i_state);
  162.     return 0;
  163. }
  164.  
  165. /* Send a buffer to serial transmitter */
  166. asy_output(dev,buf,cnt)
  167. unsigned dev;
  168. char *buf;
  169. unsigned short cnt;
  170. {
  171.     register struct dma *dp;
  172.     unsigned base;
  173.     char i_state;
  174.  
  175.     if(dev >= nasy)
  176.         return;
  177.     base = asy[dev].addr;
  178.     dp = &asy[dev].dma;
  179.     i_state = disable();
  180.     if(dp->flags){
  181.         restore(i_state);
  182.         return;    /* Already busy */
  183.     }
  184.     dp->data = buf;
  185.     dp->cnt = cnt;
  186.     dp->flags = 1;
  187.     /* Enable transmitter buffer empty interrupt and simulate
  188.      * an interrupt; this will get things rolling.
  189.      */
  190.     setbit(base+IER,IER_TxE);
  191.     asytxint(dev);
  192.     restore(i_state);
  193. }
  194. /* Receive characters from asynch line
  195.  * Returns count of characters read
  196.  */
  197. int16
  198. asy_recv(dev,buf,cnt)
  199. int16 dev;
  200. char *buf;
  201. unsigned cnt;
  202. {
  203.     unsigned tot,n;
  204.     int kbread();
  205.     char i_state;
  206.     struct fifo *fp;
  207.  
  208.     fp = &asy[dev].fifo;
  209.     tot = 0;
  210.     /* Read from serial I/O input buffer */
  211.     i_state = disable();
  212.     for(;;){
  213.         n = min(cnt,fp->cnt);
  214.         if(n == 0)
  215.             break;
  216.         n = min(n,&fp->buf[fp->bufsize] - fp->rp);
  217.         memcpy(buf,fp->rp,n);
  218.         fp->rp += n;
  219.         if(fp->rp >= &fp->buf[fp->bufsize])
  220.             fp->rp = fp->buf;
  221.         fp->cnt -= n;
  222.         buf += n;
  223.         tot += n;
  224.         cnt -= n;
  225.     }
  226.     restore(i_state);
  227.     return tot;
  228.  
  229. }
  230. /* Interrupt handler for 8250 asynch chip */
  231. void
  232. asyint(dev)
  233. unsigned dev;
  234. {
  235.     register unsigned base;
  236.     register char iir;
  237.  
  238.     base = asy[dev].addr;
  239.     while(((iir = inportb(base+IIR)) & IIR_IP) == 0){
  240.         switch(iir & IIR_ID){
  241.         case IIR_RDA:    /* Receiver interrupt */
  242.             asyrxint(dev);
  243.             break;
  244.         case IIR_THRE:    /* Transmit interrupt */
  245.             asytxint(dev);
  246.             break;
  247.         }
  248.     }
  249. }
  250. /* Process 8250 receiver interrupts */
  251. static
  252. asyrxint(dev)
  253. unsigned dev;
  254. {
  255.     unsigned base;
  256.     register struct fifo *fp;
  257.     char c;
  258.  
  259.     base = asy[dev].addr;
  260.     fp = &asy[dev].fifo;
  261.     while(inportb(base+LSR) & LSR_DR){
  262.         c = inportb(base+RBR);
  263.         /* Process incoming data;
  264.          * If buffer is full, we have no choice but
  265.          * to drop the character
  266.          */
  267.         if(fp->cnt != fp->bufsize){
  268.             *fp->wp++ = c;
  269.             if(fp->wp == &fp->buf[fp->bufsize])
  270.                 /* Wrap around */
  271.                 fp->wp = fp->buf;
  272.             fp->cnt++;
  273.         }
  274.     }
  275. }
  276. /* Handle 8250 transmitter interrupts */
  277. static
  278. asytxint(dev)
  279. unsigned dev;
  280. {
  281.     register struct dma *dp;
  282.     register unsigned base;
  283.  
  284.     base = asy[dev].addr;
  285.     dp = &asy[dev].dma;
  286.     if(!dp->flags){
  287.         /* "Shouldn't happen", but disable transmit
  288.          * interrupts anyway
  289.          */
  290.         clrbit(base+IER,IER_TxE);
  291.         return;    /* Nothing to send */
  292.     }
  293.     while(inportb(base+LSR) & LSR_THRE){
  294.         outportb(base+THR,*dp->data++);
  295.         if(--dp->cnt == 0){
  296.             dp->flags = 0;
  297.             /* Disable transmit interrupts */
  298.             clrbit(base+IER,IER_TxE);
  299.             /* Call completion interrupt here */
  300.             break;
  301.         }
  302.     }
  303. }
  304. int
  305. stxrdy(dev)
  306. int16 dev;
  307. {
  308.     return(!asy[dev].dma.flags);
  309. }
  310. /* Set bit(s) in I/O port */
  311.  
  312. setbit(port,bits)
  313. unsigned port;
  314. char bits;
  315. {
  316.     outportb(port,(char)inportb(port)|bits);
  317. }
  318. /* Clear bit(s) in I/O port */
  319. clrbit(port,bits)
  320. unsigned port;
  321. char bits;
  322. {
  323.     outportb(port,(char)(inportb(port) & ~bits));
  324. }
  325.  
  326.  
  327.